<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Jeffery Blog - 前端小蜗牛</title><meta name="keywords" content="Vue, JavaScript, Node, 组件库"><meta name="author" content="志非"><meta name="copyright" content="志非"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="让自己变得更好是解决问题的关键">
<meta property="og:type" content="website">
<meta property="og:title" content="Jeffery Blog">
<meta property="og:url" content="https://fif.gitee.io/blog/index.html">
<meta property="og:site_name" content="Jeffery Blog">
<meta property="og:description" content="让自己变得更好是解决问题的关键">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://fif.gitee.io/blog/img/home/avatar.jpeg">
<meta property="article:author" content="志非">
<meta property="article:tag" content="Vue, JavaScript, Node, 组件库">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://fif.gitee.io/blog/img/home/avatar.jpeg"><link rel="shortcut icon" href="/blog/img/home/avatar.jpeg"><link rel="canonical" href="https://fif.gitee.io/blog/"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="preconnect" href="//fonts.googleapis.com" crossorigin=""/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/blog/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/node-snackbar/dist/snackbar.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/instantsearch.js@2.10.5/dist/instantsearch.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/instantsearch.js@2.10.5/dist/instantsearch.min.js" defer></script><script async="async" src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"></script><script>(adsbygoogle = window.adsbygoogle || []).push({
  google_ad_client: '',
  enable_page_level_ads: 'true'
});</script><link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Titillium+Web&amp;display=swap" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = { 
  root: '/blog/',
  algolia: {"appId":"QYKLQ4BSGP","apiKey":"d45fc66694b4260b20711a30fdb5c4e1","indexName":"jeffery-blog","hits":{"per_page":6},"languages":{"input_placeholder":"搜索文章","hits_empty":"找不到您查询的内容：${query}","hits_stats":"找到 ${hits} 条结果，用时 ${time} 毫秒"}},
  localSearch: undefined,
  translate: {"defaultEncoding":2,"translateDelay":0,"msgToTraditionalChinese":"繁","msgToSimplifiedChinese":"簡"},
  noticeOutdate: {"limitDay":200,"position":"top","messagePrev":"本文修改于","messageNext":"天前，如果本文有一定的时效性，那么本文可能已经失效~"},
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: true,
    post: false
  },
  runtime: '天',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'mediumZoom',
  Snackbar: {"chs_to_cht":"你已切换为繁体","cht_to_chs":"你已切换为简体","day_to_night":"你已切换为深色模式","night_to_day":"你已切换为浅色模式","bgLight":"#49b1f5","bgDark":"#121212","position":"bottom-left"},
  source: {
    jQuery: 'https://cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js',
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/js/jquery.justifiedGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/css/justifiedGallery.min.css'
    },
    fancybox: {
      js: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.js',
      css: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: true,
  isanchor: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = { 
  isPost: false,
  isHome: true,
  isHighlightShrink: true,
  isToc: false,
  postUpdate: '2021-06-21 00:14:30'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    })(window)</script><meta name="generator" content="Hexo 5.4.0"><link rel="alternate" href="/blog/atom.xml" title="Jeffery Blog" type="application/atom+xml">
</head><body><div id="loading-box"><div class="loading-left-bg"></div><div class="loading-right-bg"></div><img class="load-image" src= "" data-lazy-src="/blog/img/loading.gif" alt=""/></div><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="author-avatar"><img class="avatar-img" src= "" data-lazy-src="/blog/img/home/avatar.jpeg" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="site-data"><div class="data-item is-center"><div class="data-item-link"><a href="/blog/archives/"><div class="headline">文章</div><div class="length-num">12</div></a></div></div><div class="data-item is-center"><div class="data-item-link"><a href="/blog/tags/"><div class="headline">标签</div><div class="length-num">6</div></a></div></div><div class="data-item is-center"><div class="data-item-link"><a href="/blog/categories/"><div class="headline">分类</div><div class="length-num">7</div></a></div></div></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/blog/"><i class="fa-fw fa fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/blog/archives/"><i class="fa-fw fa fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/blog/tags/"><i class="fa-fw fa fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/blog/categories/"><i class="fa-fw fa fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 媒体</span><i class="fas fa-chevron-down expand"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/blog/books/"><i class="fa-fw fas fa-book"></i><span> 阅读</span></a></li><li><a class="site-page child" href="/blog/music/"><i class="fa-fw fa fa-music"></i><span> 音乐</span></a></li><li><a class="site-page child" href="/blog/movies/"><i class="fa-fw fa fa-film"></i><span> 电影</span></a></li><li><a class="site-page child" href="/blog/gallery/"><i class="fa-fw far fa-image"></i><span> 相册</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/blog/box/"><i class="fa-fw fab fa-xbox"></i><span> 聚宝盒</span></a></div><div class="menus_item"><a class="site-page" href="/blog/talk/"><i class="fa-fw far fa-comment"></i><span> 微语</span></a></div><div class="menus_item"><a class="site-page" href="/blog/link/"><i class="fa-fw fa fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/blog/about/"><i class="fa-fw fa fa-heart"></i><span> 关于</span></a></div></div></div></div><div class="page" id="body-wrap"><header class="full_page" id="page-header" style="background-image: url('/blog/img/home/index.webp')"><nav id="nav"><span id="blog_name"><a id="site-name" href="/blog/">Jeffery Blog</a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" href="/blog/"><i class="fa-fw fa fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/blog/archives/"><i class="fa-fw fa fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/blog/tags/"><i class="fa-fw fa fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/blog/categories/"><i class="fa-fw fa fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="javascript:void(0);"><i class="fa-fw fas fa-list"></i><span> 媒体</span><i class="fas fa-chevron-down expand"></i></a><ul class="menus_item_child"><li><a class="site-page child" href="/blog/books/"><i class="fa-fw fas fa-book"></i><span> 阅读</span></a></li><li><a class="site-page child" href="/blog/music/"><i class="fa-fw fa fa-music"></i><span> 音乐</span></a></li><li><a class="site-page child" href="/blog/movies/"><i class="fa-fw fa fa-film"></i><span> 电影</span></a></li><li><a class="site-page child" href="/blog/gallery/"><i class="fa-fw far fa-image"></i><span> 相册</span></a></li></ul></div><div class="menus_item"><a class="site-page" href="/blog/box/"><i class="fa-fw fab fa-xbox"></i><span> 聚宝盒</span></a></div><div class="menus_item"><a class="site-page" href="/blog/talk/"><i class="fa-fw far fa-comment"></i><span> 微语</span></a></div><div class="menus_item"><a class="site-page" href="/blog/link/"><i class="fa-fw fa fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/blog/about/"><i class="fa-fw fa fa-heart"></i><span> 关于</span></a></div></div><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav><div id="site-info"><h1 id="site-title">Jeffery Blog</h1><div id="site-subtitle"><span id="subtitle"></span></div><div id="site_social_icons"><a class="social-icon" href="https://github.com/JefferyXZF" target="_blank" title="Github"><i class="fab fa-github"></i></a><a class="social-icon" href="https://www.yuque.com/jeffery-kkrpn/uz24n9" target="_blank" title="语雀"><i class="fa fa-folder-open"></i></a><a class="social-icon" href="https://mail.qq.com/" target="_blank" title="Email"><i class="fas fa-envelope"></i></a></div></div><div id="scroll-down"><i class="fas fa-angle-down scroll-down-effects"></i></div></header><main class="layout" id="content-inner"><div class="recent-posts" id="recent-posts"><div class="recent-post-item"><div class="post_cover left_radius"><a href="/blog/2021/05/24/tools/hexo/advanced/" title="Hexo 博客页面性能优化">     <img class="post_bg" src= "" data-lazy-src="https://gitee.com/FIF/pic-beg/raw/master/images/vue/Hexo-logo.png" onerror="this.onerror=null;this.src='/blog/img/404.jpg'" alt="Hexo 博客页面性能优化"></a></div><div class="recent-post-info"><a class="article-title" href="/blog/2021/05/24/tools/hexo/advanced/" title="Hexo 博客页面性能优化">Hexo 博客页面性能优化</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2021-05-23T16:00:00.000Z" title="发表于 2021-05-24 00:00:00">2021-05-24</time></span><span class="article-meta"><span class="article-meta__separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/blog/categories/hexo/">hexo</a></span><span class="article-meta tags"><span class="article-meta__separator">|</span><i class="fas fa-tag"></i><a class="article-meta__tags" href="/blog/tags/hexo/">hexo</a></span><span class="article-meta"><span class="article-meta__separator">|</span><i class="fas fa-comments"></i><a href="/blog/2021/05/24/tools/hexo/advanced/#post-comment" itemprop="discussionUrl"><span class="valine-comment-count" data-xid="/blog/2021/05/24/tools/hexo/advanced/" itemprop="commentCount"></span></a><span class="article-meta-label"> 条评论</span></span></div><div class="content">前言前段时间使用 hexo 和 butterfly 主题搭建完博客后，发现页面的访问性能很慢，交互体验非常不友好，很影响看博客和写文章的心情，接下来想办法优化博客页面访问的性能。

性能分析
从浏览器控制台可以分析出，影响页面访问的性能主要有以下几点：

使用网络图片的 CDN 资源加载慢
 JS 资源加载阻塞页面的渲染
图片太大，一起加载太多下载时间慢
……

经过分析，主要是静态资源加载的问题，接下来知道如何优化页面了：

将 CDN 资源改为 本地资源

压缩图片上传，图片使用懒加载

JS 非重要资源使用异步加载，或将其放在 body 尾部

静态资源体积压缩

减少接口请求

…


性能优化将网络图片改为本地资源如果将图片下载下来改为本地图片，要手动修改路径，步骤很繁琐，同时太多图片放在本地，项目的体积也会非常的大，那么有没有办法将图片放在图片服务器进来统一管理，可是图片服务器需要资源(MONEY)，不过幸遇的是可以使用 gitee 仓库来管理我们的图片，gitee 网络在国内访问还是很OK的
使用  PicGo 和 [Typora]P](https://typora.io ...</div></div></div><div class="recent-post-item"><div class="post_cover right_radius"><a href="/blog/2021/05/14/vue/vue-code-9.event/" title="（Vue源码七）Vue 事件">     <img class="post_bg" src= "" data-lazy-src="https://gitee.com/FIF/pic-beg/raw/master/images/vue/components.png" onerror="this.onerror=null;this.src='/blog/img/404.jpg'" alt="（Vue源码七）Vue 事件"></a></div><div class="recent-post-info"><a class="article-title" href="/blog/2021/05/14/vue/vue-code-9.event/" title="（Vue源码七）Vue 事件">（Vue源码七）Vue 事件</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2021-05-13T16:00:00.000Z" title="发表于 2021-05-14 00:00:00">2021-05-14</time></span><span class="article-meta"><span class="article-meta__separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/blog/categories/%E5%89%8D%E7%AB%AF/">前端</a><i class="fas fa-angle-right"></i><a class="article-meta__categories" href="/blog/categories/%E5%89%8D%E7%AB%AF/vue/">vue</a><i class="fas fa-angle-right"></i><a class="article-meta__categories" href="/blog/categories/%E5%89%8D%E7%AB%AF/vue/vue-%E6%BA%90%E7%A0%81/">vue 源码</a></span><span class="article-meta tags"><span class="article-meta__separator">|</span><i class="fas fa-tag"></i><a class="article-meta__tags" href="/blog/tags/vue/">vue</a><span class="article-meta__link">•</span><a class="article-meta__tags" href="/blog/tags/vue-%E6%BA%90%E7%A0%81/">vue 源码</a></span><span class="article-meta"><span class="article-meta__separator">|</span><i class="fas fa-comments"></i><a href="/blog/2021/05/14/vue/vue-code-9.event/#post-comment" itemprop="discussionUrl"><span class="valine-comment-count" data-xid="/blog/2021/05/14/vue/vue-code-9.event/" itemprop="commentCount"></span></a><span class="article-meta-label"> 条评论</span></span></div><div class="content">概述在日常开发中，可以在元素中绑定原生事件处理交互，例如 @click=***，也可以在组件中利用自定义事件实现父子间的通信，那原生 dom 事件和自定义事件有什么不同的地方吗，实现通信的原理又是什么，带着问题，来研究分析事件原理。
模板编译我们使用v-on或者@在模板上绑定事件，因此对事件的第一步处理，就是在编译阶段对事件指令做处理。
1234567891011121314151617181920&lt;div id=&quot;app&quot;&gt;    &lt;div v-on:click.stop=&quot;doThis&quot;&gt;点击&lt;/div&gt;    &lt;span&gt;&#123;&#123;count&#125;&#125;&lt;/span&gt;&lt;/div&gt;&lt;script&gt;var vm = new Vue(&#123;    el: &#x27;#app&#x27;,    data() &#123;        return &#123;            count: 1        &#125;  ...</div></div></div><div class="recent-post-item"><div class="post_cover left_radius"><a href="/blog/2021/05/04/vue/vue-code-8.component/" title="（Vue源码六）Vue 组件原理分析">     <img class="post_bg" src= "" data-lazy-src="https://gitee.com/FIF/pic-beg/raw/master/images/vue/components.png" onerror="this.onerror=null;this.src='/blog/img/404.jpg'" alt="（Vue源码六）Vue 组件原理分析"></a></div><div class="recent-post-info"><a class="article-title" href="/blog/2021/05/04/vue/vue-code-8.component/" title="（Vue源码六）Vue 组件原理分析">（Vue源码六）Vue 组件原理分析</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2021-05-03T16:00:00.000Z" title="发表于 2021-05-04 00:00:00">2021-05-04</time></span><span class="article-meta"><span class="article-meta__separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/blog/categories/%E5%89%8D%E7%AB%AF/">前端</a><i class="fas fa-angle-right"></i><a class="article-meta__categories" href="/blog/categories/%E5%89%8D%E7%AB%AF/vue/">vue</a><i class="fas fa-angle-right"></i><a class="article-meta__categories" href="/blog/categories/%E5%89%8D%E7%AB%AF/vue/vue-%E6%BA%90%E7%A0%81/">vue 源码</a></span><span class="article-meta tags"><span class="article-meta__separator">|</span><i class="fas fa-tag"></i><a class="article-meta__tags" href="/blog/tags/vue/">vue</a><span class="article-meta__link">•</span><a class="article-meta__tags" href="/blog/tags/vue-%E6%BA%90%E7%A0%81/">vue 源码</a></span><span class="article-meta"><span class="article-meta__separator">|</span><i class="fas fa-comments"></i><a href="/blog/2021/05/04/vue/vue-code-8.component/#post-comment" itemprop="discussionUrl"><span class="valine-comment-count" data-xid="/blog/2021/05/04/vue/vue-code-8.component/" itemprop="commentCount"></span></a><span class="article-meta-label"> 条评论</span></span></div><div class="content">组件渲染流程图
思考
全局注册组件和局部注册组件原理，它们之间的异同是什么？
组件是如何渲染成DOM？
组件的 $root, $parent, $children 是如何建立的层级关系？
mixins, extends 定义的组件选项 components 是如何被使用的？
组件的两种使用场景：函数式组件和异步组件，它们的实现原理是什么，解决什么问题？

带着这几个问题一起来分析 Vue 组件的实现原理。
概要使用 vue 框架开发页面，其实本质上就是写一个个组件。独立的组件将页面结构化，开发者可以专注于某个功能的开发和扩展；同时组件的设计理念又使得功能具有复用性，不同的页面可以进行组件功能的共享。
了解组件注册的实现思路，分析组件渲染的流程；知道组件和组件之间是如何建立联系的，组件之间是如何通信的，组件的使用场景有哪些，掌握这些底层的实现思路对于在解决Vue组件相关问题上有明显的帮助。
组件两种注册方式Vue 组件在使用之前需要进行注册，而注册的方式有两种，全局注册和局部注册。在进入源码分析之前，先回忆一下两者的用法，以便后续掌握两者的差异。
全局注册
Vue.component(  ...</div></div></div><div class="recent-post-item"><div class="post_cover right_radius"><a href="/blog/2021/04/30/vue/vue-code-7-compiler/" title="（Vue源码五）Vue 编译原理">     <img class="post_bg" src= "" data-lazy-src="https://gitee.com/FIF/pic-beg/raw/master/images/vue/vuetemplate.jpg" onerror="this.onerror=null;this.src='/blog/img/404.jpg'" alt="（Vue源码五）Vue 编译原理"></a></div><div class="recent-post-info"><a class="article-title" href="/blog/2021/04/30/vue/vue-code-7-compiler/" title="（Vue源码五）Vue 编译原理">（Vue源码五）Vue 编译原理</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2021-04-29T16:00:00.000Z" title="发表于 2021-04-30 00:00:00">2021-04-30</time></span><span class="article-meta"><span class="article-meta__separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/blog/categories/%E5%89%8D%E7%AB%AF/">前端</a><i class="fas fa-angle-right"></i><a class="article-meta__categories" href="/blog/categories/%E5%89%8D%E7%AB%AF/vue/">vue</a><i class="fas fa-angle-right"></i><a class="article-meta__categories" href="/blog/categories/%E5%89%8D%E7%AB%AF/vue/vue-%E6%BA%90%E7%A0%81/">vue 源码</a></span><span class="article-meta tags"><span class="article-meta__separator">|</span><i class="fas fa-tag"></i><a class="article-meta__tags" href="/blog/tags/vue/">vue</a><span class="article-meta__link">•</span><a class="article-meta__tags" href="/blog/tags/vue-%E6%BA%90%E7%A0%81/">vue 源码</a></span><span class="article-meta"><span class="article-meta__separator">|</span><i class="fas fa-comments"></i><a href="/blog/2021/04/30/vue/vue-code-7-compiler/#post-comment" itemprop="discussionUrl"><span class="valine-comment-count" data-xid="/blog/2021/04/30/vue/vue-code-7-compiler/" itemprop="commentCount"></span></a><span class="article-meta-label"> 条评论</span></span></div><div class="content">概念平时使用模板时，可以在模板中使用变量、表达式或者指令等，如 v-on、v-if，这些语法在 html 中是不存在的，那 vue 中为什么可以实现？这就归功于模板编译功能。
Vue 内置的编译器或 vue-loader 插件带有编译功能，它把&lt;template&gt;&lt;/template&gt;标签中类似于原生HTML的内容进行编译，本质上通过正则匹配，生成渲染函数，也就是render函数，而render函数会将模板内容生成对应的VNode，而VNode再经过patch过程创建真实的DOM节点并插入到视图中， 最终完成视图的渲染更新。

从图中我们也可以看到，模板编译过程就是把用户写的模板经过一系列处理最终生成render函数的过程。
模板渲染过程
从执行流程图中我们可以知道，在 $mount 挂载会执行 compileToFunctions 方法，compile 进行模板编译,  编译过程主要做了三件事：

parse :  通过正则匹配解析模板字符串生成 ast，它是一个抽象语法树，ast在线演示工具
optimize: 优化语法树， 打上静态节点或根静态节点标识
g ...</div></div></div><div class="recent-post-item"><div class="post_cover left_radius"><a href="/blog/2021/04/27/vue/vue-code-6.reactive/" title="（Vue源码四）数据响应式原理">     <img class="post_bg" src= "" data-lazy-src="https://gitee.com/FIF/pic-beg/raw/master/images/vue/mvvm.png" onerror="this.onerror=null;this.src='/blog/img/404.jpg'" alt="（Vue源码四）数据响应式原理"></a></div><div class="recent-post-info"><a class="article-title" href="/blog/2021/04/27/vue/vue-code-6.reactive/" title="（Vue源码四）数据响应式原理">（Vue源码四）数据响应式原理</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2021-04-26T16:00:00.000Z" title="发表于 2021-04-27 00:00:00">2021-04-27</time></span><span class="article-meta"><span class="article-meta__separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/blog/categories/%E5%89%8D%E7%AB%AF/">前端</a><i class="fas fa-angle-right"></i><a class="article-meta__categories" href="/blog/categories/%E5%89%8D%E7%AB%AF/vue/">vue</a><i class="fas fa-angle-right"></i><a class="article-meta__categories" href="/blog/categories/%E5%89%8D%E7%AB%AF/vue/vue-%E6%BA%90%E7%A0%81/">vue 源码</a></span><span class="article-meta tags"><span class="article-meta__separator">|</span><i class="fas fa-tag"></i><a class="article-meta__tags" href="/blog/tags/vue/">vue</a><span class="article-meta__link">•</span><a class="article-meta__tags" href="/blog/tags/vue-%E6%BA%90%E7%A0%81/">vue 源码</a></span><span class="article-meta"><span class="article-meta__separator">|</span><i class="fas fa-comments"></i><a href="/blog/2021/04/27/vue/vue-code-6.reactive/#post-comment" itemprop="discussionUrl"><span class="valine-comment-count" data-xid="/blog/2021/04/27/vue/vue-code-6.reactive/" itemprop="commentCount"></span></a><span class="article-meta-label"> 条评论</span></span></div><div class="content">思考
Observer， Watcher， Dep 3个类具体的作用、以及他们之间的关系。
props,  data，watch，computed 响应式原理的实现？
Dep 作为依赖管理的类，在什么时候进行实例化收集依赖？
Dep 收集了什么类型的依赖？即 watcher 作为依赖的分类有哪些，分别是什么场景，以及区别在哪里？
Observer 这个类具体对 getter, setter 方法做了哪些事情？
手写的 watch 和页面数据渲染监听的 watch 如果同时监听到数据的变化，优先级怎么排？
有了依赖的收集是不是还有依赖的解除，依赖解除的意义在哪里？

带着这些问题，来分析 Vue 响应式实现原理
响应式原理流程图分析先从全局了解整个响应式原理的流程，再从局部分析props、 data、watcher、computed 响应式的实现，由浅入深，逐渐深入



从上面流程图，我们可以了解到 Observer、Watcher、Dep 三者的作用已经关系：

Observer 类：实例化 Observer 类通过 Object.defineProperty 对数据的getter, ...</div></div></div><div class="recent-post-item"><div class="post_cover right_radius"><a href="/blog/2021/04/24/tools/gitlab/index/" title="Gitlab webhook 配置企业微信机器人">     <img class="post_bg" src= "" data-lazy-src="https://gitee.com/FIF/pic-beg/raw/master/images/vue/Hexo-logo.png" onerror="this.onerror=null;this.src='/blog/img/404.jpg'" alt="Gitlab webhook 配置企业微信机器人"></a></div><div class="recent-post-info"><a class="article-title" href="/blog/2021/04/24/tools/gitlab/index/" title="Gitlab webhook 配置企业微信机器人">Gitlab webhook 配置企业微信机器人</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2021-04-23T16:00:00.000Z" title="发表于 2021-04-24 00:00:00">2021-04-24</time></span><span class="article-meta"><span class="article-meta__separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/blog/categories/hexo/">hexo</a></span><span class="article-meta tags"><span class="article-meta__separator">|</span><i class="fas fa-tag"></i><a class="article-meta__tags" href="/blog/tags/hexo/">hexo</a></span><span class="article-meta"><span class="article-meta__separator">|</span><i class="fas fa-comments"></i><a href="/blog/2021/04/24/tools/gitlab/index/#post-comment" itemprop="discussionUrl"><span class="valine-comment-count" data-xid="/blog/2021/04/24/tools/gitlab/index/" itemprop="commentCount"></span></a><span class="article-meta-label"> 条评论</span></span></div><div class="content">Gitlab webhook 配置企业微信机器人概述使用 gitlab 进行代码审查时，发现团队成员提交的代码不是很规范，有时候合并别的分支到开发分支造成分支污染，也不知道团队成员在什么时候提交的代码，线下审查代码和沟通很费时。为了提高代码审查的效率，事时查看团队成员提交合并的代码是否正确规范，于是想到使用 GitLab 提供的 webhook 钩子，搭建中间服务，利用企业微信机器人进行提醒，因为搭建 CI/CD 工具有点难，也有点大材小用，基于时间和精力成本。选择了前者。前前后后差不多用了两个星期完成。
工作流程Gitlab在 Gitlab 的 Integrations 面板创建一条 webhook 记录，只有管理员才有权限创建，记录包括中间服务 URL 地址，勾选触发的事件，以及是否需要 SSL验证（可选）。


创建webhook成功后，当往 gitlab 仓库进行 当 push、tag push、merge request、pipeline 等操作，会触发勾选的钩子函数执行，携带 git 提交的信息的相关信息向 URL 地址发起一个请求，这时候我们搭建的中间服务就起作用了。它请 ...</div></div></div><div class="recent-post-item"><div class="post_cover left_radius"><a href="/blog/2021/04/23/vue/vue-code-5.mergeOptions/" title="（Vue源码三）Vue 丰富的选项合并策略">     <img class="post_bg" src= "" data-lazy-src="https://gitee.com/FIF/pic-beg/raw/master/images/vue/vue-highcharts_1200.webp" onerror="this.onerror=null;this.src='/blog/img/404.jpg'" alt="（Vue源码三）Vue 丰富的选项合并策略"></a></div><div class="recent-post-info"><a class="article-title" href="/blog/2021/04/23/vue/vue-code-5.mergeOptions/" title="（Vue源码三）Vue 丰富的选项合并策略">（Vue源码三）Vue 丰富的选项合并策略</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2021-04-22T16:00:00.000Z" title="发表于 2021-04-23 00:00:00">2021-04-23</time></span><span class="article-meta"><span class="article-meta__separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/blog/categories/%E5%89%8D%E7%AB%AF/">前端</a><i class="fas fa-angle-right"></i><a class="article-meta__categories" href="/blog/categories/%E5%89%8D%E7%AB%AF/vue/">vue</a><i class="fas fa-angle-right"></i><a class="article-meta__categories" href="/blog/categories/%E5%89%8D%E7%AB%AF/vue/vue-%E6%BA%90%E7%A0%81/">vue 源码</a></span><span class="article-meta tags"><span class="article-meta__separator">|</span><i class="fas fa-tag"></i><a class="article-meta__tags" href="/blog/tags/vue/">vue</a><span class="article-meta__link">•</span><a class="article-meta__tags" href="/blog/tags/vue-%E6%BA%90%E7%A0%81/">vue 源码</a></span><span class="article-meta"><span class="article-meta__separator">|</span><i class="fas fa-comments"></i><a href="/blog/2021/04/23/vue/vue-code-5.mergeOptions/#post-comment" itemprop="discussionUrl"><span class="valine-comment-count" data-xid="/blog/2021/04/23/vue/vue-code-5.mergeOptions/" itemprop="commentCount"></span></a><span class="article-meta-label"> 条评论</span></span></div><div class="content">前言选项合并在执行 Vue 实例化、Vue.mixin、Vue.extend、组件内部定义 extends 、mixins 等场景使用，目的实现功能的扩展、复用。
选项合并使用场景_init 初始化合并选项new Vue 执行 _init 方法进行选项合并
123456789101112131415Vue.prototype._init = function (options) &#123;  // ...  if (options &amp;&amp; options._isComponent) &#123; // 初始化内部子组件    initInternalComponent(vm, options)  &#125; else &#123;    // 根组件选项合并，将合并后的选项赋值给实例的 $options 属性    vm.$options = mergeOptions(      resolveConstructorOptions(vm.constructor), // 返回 Vue 构造函数自身的配置项      options || &#123;&#125;,   ...</div></div></div><div class="recent-post-item"><div class="post_cover right_radius"><a href="/blog/2021/04/17/vue/vue-code-4.debugger/" title="（Vue源码二）Vue实例挂载流程">     <img class="post_bg" src= "" data-lazy-src="https://gitee.com/FIF/pic-beg/raw/master/images/vue/1_b2Ig4HR2UOQEV5I2QnQrrw.png" onerror="this.onerror=null;this.src='/blog/img/404.jpg'" alt="（Vue源码二）Vue实例挂载流程"></a></div><div class="recent-post-info"><a class="article-title" href="/blog/2021/04/17/vue/vue-code-4.debugger/" title="（Vue源码二）Vue实例挂载流程">（Vue源码二）Vue实例挂载流程</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2021-04-16T16:00:00.000Z" title="发表于 2021-04-17 00:00:00">2021-04-17</time></span><span class="article-meta"><span class="article-meta__separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/blog/categories/%E5%89%8D%E7%AB%AF/">前端</a><i class="fas fa-angle-right"></i><a class="article-meta__categories" href="/blog/categories/%E5%89%8D%E7%AB%AF/vue/">vue</a><i class="fas fa-angle-right"></i><a class="article-meta__categories" href="/blog/categories/%E5%89%8D%E7%AB%AF/vue/vue-%E6%BA%90%E7%A0%81/">vue 源码</a></span><span class="article-meta tags"><span class="article-meta__separator">|</span><i class="fas fa-tag"></i><a class="article-meta__tags" href="/blog/tags/vue/">vue</a><span class="article-meta__link">•</span><a class="article-meta__tags" href="/blog/tags/vue-%E6%BA%90%E7%A0%81/">vue 源码</a></span><span class="article-meta"><span class="article-meta__separator">|</span><i class="fas fa-comments"></i><a href="/blog/2021/04/17/vue/vue-code-4.debugger/#post-comment" itemprop="discussionUrl"><span class="valine-comment-count" data-xid="/blog/2021/04/17/vue/vue-code-4.debugger/" itemprop="commentCount"></span></a><span class="article-meta-label"> 条评论</span></span></div><div class="content">Vue函数挂载APIVue 之所以能实现各种高级的功能，比如响应式、编译、组件渲染，和它身上拥有丰富的 API 有关，Vue 在实例化前会挂载 API ，它的 API 分为全局 API 和原型方法，下面从入口文件到Vue构造函数挂载 API 的流程图：

initGlobalAPI挂载全局方法initGlobalAPI 挂载全局方法，它的入口文件在 src/core/index.js
12345import Vue from &#x27;./instance/index&#x27;import &#123; initGlobalAPI &#125; from &#x27;./global-api/index&#x27;initGlobalAPI(Vue)export default Vue

initGlobalAPI()函数定义在 src/core/global-api/index.js 中：
12345678910111213141516171819202122232425262728293031323334353637383940414243export function ini ...</div></div></div><div class="recent-post-item"><div class="post_cover left_radius"><a href="/blog/2021/04/12/vue/vue-code-3.build/" title="（Vue源码一）Vue 源码设计和构建流程">     <img class="post_bg" src= "" data-lazy-src="https://gitee.com/FIF/pic-beg/raw/master/images/vue/Vue.js-i18n-768x512.jpg" onerror="this.onerror=null;this.src='/blog/img/404.jpg'" alt="（Vue源码一）Vue 源码设计和构建流程"></a></div><div class="recent-post-info"><a class="article-title" href="/blog/2021/04/12/vue/vue-code-3.build/" title="（Vue源码一）Vue 源码设计和构建流程">（Vue源码一）Vue 源码设计和构建流程</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2021-04-11T16:00:00.000Z" title="发表于 2021-04-12 00:00:00">2021-04-12</time></span><span class="article-meta"><span class="article-meta__separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/blog/categories/%E5%89%8D%E7%AB%AF/">前端</a><i class="fas fa-angle-right"></i><a class="article-meta__categories" href="/blog/categories/%E5%89%8D%E7%AB%AF/vue/">vue</a><i class="fas fa-angle-right"></i><a class="article-meta__categories" href="/blog/categories/%E5%89%8D%E7%AB%AF/vue/vue-%E6%BA%90%E7%A0%81/">vue 源码</a></span><span class="article-meta tags"><span class="article-meta__separator">|</span><i class="fas fa-tag"></i><a class="article-meta__tags" href="/blog/tags/vue/">vue</a><span class="article-meta__link">•</span><a class="article-meta__tags" href="/blog/tags/vue-%E6%BA%90%E7%A0%81/">vue 源码</a></span><span class="article-meta"><span class="article-meta__separator">|</span><i class="fas fa-comments"></i><a href="/blog/2021/04/12/vue/vue-code-3.build/#post-comment" itemprop="discussionUrl"><span class="valine-comment-count" data-xid="/blog/2021/04/12/vue/vue-code-3.build/" itemprop="commentCount"></span></a><span class="article-meta-label"> 条评论</span></span></div><div class="content">介绍本篇Vue2.6.12源码分析文章由观看Vue.js源码全方位深入解析视频，阅读深入浅出Vue.js书籍以及参考其他Vue源码分析博客而来，阅读视频和书籍请支持正版。
Vue发展简史
2013年7月，Vue.js在Github上第一次提交，此时名字叫做Element，后来被改名为Seed.js，到现在的Vue.js。
2013年12月，Github发布0.6版本，并正式更名为Vue.js。
2014年2月，在Hacker News网站上时候首次公开。
2015年10月，Vue.js发布1.0.0版本。
2016年10月，Vue.js发布2.0版本。
2020年9月18日，Vue.js发布3.0版本。

Vue版本变化Vue2.0版本和Vue1.0版本相比引入了很多特性：

Virtual DOM虚拟DOM。
支持JSX语法。
支持TypeScript。
支持服务端渲染ssr。
提供跨平台能力weex。

正确理解虚拟DOM：Vue中的虚拟DOM借鉴了开源库snabbdom的实现，并根据自身特色添加了许多特性。引入虚拟DOM的一个很重要的好处是：绝大部分情况下，组件渲染变得更快了，而 ...</div></div></div><div class="recent-post-item"><div class="post_cover right_radius"><a href="/blog/2021/04/11/vue/vue-code-2.rollup/" title="rollup 教程">     <img class="post_bg" src= "" data-lazy-src="https://www.rollupjs.com/img/twitter-card.jpg" onerror="this.onerror=null;this.src='/blog/img/404.jpg'" alt="rollup 教程"></a></div><div class="recent-post-info"><a class="article-title" href="/blog/2021/04/11/vue/vue-code-2.rollup/" title="rollup 教程">rollup 教程</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2021-04-10T16:00:00.000Z" title="发表于 2021-04-11 00:00:00">2021-04-11</time></span><span class="article-meta"><span class="article-meta__separator">|</span><i class="fas fa-inbox"></i><a class="article-meta__categories" href="/blog/categories/%E5%B7%A5%E5%85%B7/">工具</a><i class="fas fa-angle-right"></i><a class="article-meta__categories" href="/blog/categories/%E5%B7%A5%E5%85%B7/%E6%9E%84%E5%BB%BA%E5%B7%A5%E5%85%B7/">构建工具</a></span><span class="article-meta tags"><span class="article-meta__separator">|</span><i class="fas fa-tag"></i><a class="article-meta__tags" href="/blog/tags/vue/">vue</a><span class="article-meta__link">•</span><a class="article-meta__tags" href="/blog/tags/rollup/">rollup</a></span><span class="article-meta"><span class="article-meta__separator">|</span><i class="fas fa-comments"></i><a href="/blog/2021/04/11/vue/vue-code-2.rollup/#post-comment" itemprop="discussionUrl"><span class="valine-comment-count" data-xid="/blog/2021/04/11/vue/vue-code-2.rollup/" itemprop="commentCount"></span></a><span class="article-meta-label"> 条评论</span></span></div><div class="content">概述vue 源码的构建工具使用的是 Rollup ，它是一个 JavaScript 模块打包器，可以将小块代码编译成大块复杂的代码。
Rollup 对代码模块使用新的标准化格式，这些标准都包含在 JavaScript 的 ES6 版本中，而不是以前的特殊解决方案，如 CommonJS 和 AMD 。ES6 模块可以使你自由、无缝地使用你最喜爱的 library 中那些最有用独立函数，而你的项目不必携带其他未使用的代码。ES6 模块最终还是要由浏览器原生实现，但当前 Rollup 可以使你提前体验。
快速入门指南安装1234567// 全局安装npm install rollup --globalyarn add  rollup --global// 局部安装npm install rollup -Dyarn add rollup -D

Rollup 可以通过命令行接口(command line interface)配合可选配置文件(optional configuration file)来调用，或者可以通过 JavaScript API 来调用。
运行 rollup --help 或 ...</div></div></div><nav id="pagination"><div class="pagination"><span class="page-number current">1</span><a class="page-number" href="/blog/page/2/#content-inner">2</a><a class="extend next" rel="next" href="/blog/page/2/#content-inner"><i class="fas fa-chevron-right fa-fw"></i></a></div></nav></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="card-info-avatar is-center"><img class="avatar-img" src= "" data-lazy-src="/blog/img/home/avatar.jpeg" onerror="this.onerror=null;this.src='/blog/img/friend_404.gif'" alt="avatar"/><div class="author-info__name">志非</div><div class="author-info__description">自己变得更好，生活才会更美好</div></div><div class="card-info-data"><div class="card-info-data-item is-center"><a href="/blog/archives/"><div class="headline">文章</div><div class="length-num">12</div></a></div><div class="card-info-data-item is-center"><a href="/blog/tags/"><div class="headline">标签</div><div class="length-num">6</div></a></div><div class="card-info-data-item is-center"><a href="/blog/categories/"><div class="headline">分类</div><div class="length-num">7</div></a></div></div><a class="button--animated" id="card-info-btn" target="_blank" rel="noopener" href="https://github.com/JefferyXZF"><i class="fab fa-github"></i><span>Follow Me</span></a><div class="card-info-social-icons is-center"><a class="social-icon" href="https://github.com/JefferyXZF" target="_blank" title="Github"><i class="fab fa-github"></i></a><a class="social-icon" href="https://www.yuque.com/jeffery-kkrpn/uz24n9" target="_blank" title="语雀"><i class="fa fa-folder-open"></i></a><a class="social-icon" href="https://mail.qq.com/" target="_blank" title="Email"><i class="fas fa-envelope"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn card-announcement-animation"></i><span>公告</span></div><div class="announcement_content">越努力越幸运</div></div><div class="sticky_layout"><script defer="defer" data-pjax="data-pjax" src="/blog/js/card_clock.js"></script><div class="card-widget card-clock"><div id="clock"><img v-if="clockshow == &quot;false&quot;" alt="" src= "" data-lazy-src="/blog/img/weather/loading.gif" height="120px" width="100%"/><table class="clock" v-if="clockshow"><tbody><tr><td class="clockdate">{{date}}</td><td class="weatherimg"><img id="weatherimg" :src="weatherimg" alt=""/></td><td class="temperature">{{temperature}}</td><td class="humidityimg"><img id="humidityimg" :src="humidityimg" alt=""/></td><td class="humidity">{{humidity}}</td></tr><tr class="time"><td colspan="5">{{time}}</td></tr><tr><td class="usaqi" colspan="1"><span>{{ip}}</span></td><td class="city" colspan="2">{{city}}</td><td class="daylight" colspan="2">{{daylight}}</td></tr></tbody></table></div></div><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item"><a class="thumbnail" href="/blog/2021/05/24/tools/hexo/advanced/" title="Hexo 博客页面性能优化"><img src= "" data-lazy-src="https://gitee.com/FIF/pic-beg/raw/master/images/vue/Hexo-logo.png" onerror="this.onerror=null;this.src='/blog/img/404.jpg'" alt="Hexo 博客页面性能优化"/></a><div class="content"><a class="title" href="/blog/2021/05/24/tools/hexo/advanced/" title="Hexo 博客页面性能优化">Hexo 博客页面性能优化</a><time datetime="2021-05-23T16:00:00.000Z" title="发表于 2021-05-24 00:00:00">2021-05-24</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/blog/2021/05/14/vue/vue-code-9.event/" title="（Vue源码七）Vue 事件"><img src= "" data-lazy-src="https://gitee.com/FIF/pic-beg/raw/master/images/vue/components.png" onerror="this.onerror=null;this.src='/blog/img/404.jpg'" alt="（Vue源码七）Vue 事件"/></a><div class="content"><a class="title" href="/blog/2021/05/14/vue/vue-code-9.event/" title="（Vue源码七）Vue 事件">（Vue源码七）Vue 事件</a><time datetime="2021-05-13T16:00:00.000Z" title="发表于 2021-05-14 00:00:00">2021-05-14</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/blog/2021/05/04/vue/vue-code-8.component/" title="（Vue源码六）Vue 组件原理分析"><img src= "" data-lazy-src="https://gitee.com/FIF/pic-beg/raw/master/images/vue/components.png" onerror="this.onerror=null;this.src='/blog/img/404.jpg'" alt="（Vue源码六）Vue 组件原理分析"/></a><div class="content"><a class="title" href="/blog/2021/05/04/vue/vue-code-8.component/" title="（Vue源码六）Vue 组件原理分析">（Vue源码六）Vue 组件原理分析</a><time datetime="2021-05-03T16:00:00.000Z" title="发表于 2021-05-04 00:00:00">2021-05-04</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/blog/2021/04/30/vue/vue-code-7-compiler/" title="（Vue源码五）Vue 编译原理"><img src= "" data-lazy-src="https://gitee.com/FIF/pic-beg/raw/master/images/vue/vuetemplate.jpg" onerror="this.onerror=null;this.src='/blog/img/404.jpg'" alt="（Vue源码五）Vue 编译原理"/></a><div class="content"><a class="title" href="/blog/2021/04/30/vue/vue-code-7-compiler/" title="（Vue源码五）Vue 编译原理">（Vue源码五）Vue 编译原理</a><time datetime="2021-04-29T16:00:00.000Z" title="发表于 2021-04-30 00:00:00">2021-04-30</time></div></div><div class="aside-list-item"><a class="thumbnail" href="/blog/2021/04/27/vue/vue-code-6.reactive/" title="（Vue源码四）数据响应式原理"><img src= "" data-lazy-src="https://gitee.com/FIF/pic-beg/raw/master/images/vue/mvvm.png" onerror="this.onerror=null;this.src='/blog/img/404.jpg'" alt="（Vue源码四）数据响应式原理"/></a><div class="content"><a class="title" href="/blog/2021/04/27/vue/vue-code-6.reactive/" title="（Vue源码四）数据响应式原理">（Vue源码四）数据响应式原理</a><time datetime="2021-04-26T16:00:00.000Z" title="发表于 2021-04-27 00:00:00">2021-04-27</time></div></div></div></div><div class="card-widget" id="card-newest-comments"><div class="item-headline"><i class="fas fa-bolt"></i><span>最新评论</span></div><div class="aside-list"><span>正在加载中...</span></div></div><div class="card-widget card-categories"><div class="item-headline">
            <i class="fas fa-folder-open"></i>
            <span>分类</span>
            
            </div>
            <ul class="card-category-list" id="aside-cat-list">
            <li class="card-category-list-item "><a class="card-category-list-link" href="/blog/categories/hexo/"><span class="card-category-list-name">hexo</span><span class="card-category-list-count">2</span></a></li><li class="card-category-list-item "><a class="card-category-list-link" href="/blog/categories/npm/"><span class="card-category-list-name">npm</span><span class="card-category-list-count">1</span></a></li><li class="card-category-list-item "><a class="card-category-list-link" href="/blog/categories/%E5%89%8D%E7%AB%AF/"><span class="card-category-list-name">前端</span><span class="card-category-list-count">8</span></a><ul class="card-category-list child"><li class="card-category-list-item "><a class="card-category-list-link" href="/blog/categories/%E5%89%8D%E7%AB%AF/vue/"><span class="card-category-list-name">vue</span><span class="card-category-list-count">8</span></a><ul class="card-category-list child"><li class="card-category-list-item "><a class="card-category-list-link" href="/blog/categories/%E5%89%8D%E7%AB%AF/vue/vue-%E6%BA%90%E7%A0%81/"><span class="card-category-list-name">vue 源码</span><span class="card-category-list-count">7</span></a></li></ul></li></ul></li><li class="card-category-list-item "><a class="card-category-list-link" href="/blog/categories/%E5%B7%A5%E5%85%B7/"><span class="card-category-list-name">工具</span><span class="card-category-list-count">1</span></a><ul class="card-category-list child"><li class="card-category-list-item "><a class="card-category-list-link" href="/blog/categories/%E5%B7%A5%E5%85%B7/%E6%9E%84%E5%BB%BA%E5%B7%A5%E5%85%B7/"><span class="card-category-list-name">构建工具</span><span class="card-category-list-count">1</span></a></li></ul></li>
            </ul></div><div class="card-widget card-tags"><div class="item-headline"><i class="fas fa-tags"></i><span>标签</span></div><div class="card-tag-cloud"><a href="/blog/tags/vue/" style="font-size: 1.45em; color: rgb(138, 55, 128)">vue</a><a href="/blog/tags/npm/" style="font-size: 1.15em; color: rgb(29, 140, 164)">npm</a><a href="/blog/tags/rollup/" style="font-size: 1.15em; color: rgb(47, 31, 17)">rollup</a><a href="/blog/tags/vue-%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/" style="font-size: 1.15em; color: rgb(42, 185, 68)">vue 最佳实践</a><a href="/blog/tags/hexo/" style="font-size: 1.25em; color: rgb(167, 49, 97)">hexo</a><a href="/blog/tags/vue-%E6%BA%90%E7%A0%81/" style="font-size: 1.35em; color: rgb(118, 96, 30)">vue 源码</a></div></div><div class="card-widget card-archives"><div class="item-headline"><i class="fas fa-archive"></i><span>归档</span></div><ul class="card-archive-list"><li class="card-archive-list-item"><a class="card-archive-list-link" href="/blog/archives/2021/05/"><span class="card-archive-list-date">五月 2021</span><span class="card-archive-list-count">3</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/blog/archives/2021/04/"><span class="card-archive-list-date">四月 2021</span><span class="card-archive-list-count">9</span></a></li></ul></div><div class="card-widget user-map" id="user-map"><div class="item-headline"><i class="fas fa-heartbeat"></i><span>访客地图</span></div><div class="item-content"><script defer type="text/javascript" id="clstr_globe" src="/blog/js/clustrmaps.globe.js"></script></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="copyright">&copy;2021 By 志非</div><div class="footer_custom_text">Hi, welcome to my <a href="/">blog</a>!</div><div id="workboard"></div><script async="async" src="/blog/js/runtime.js"></script></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="translateLink" type="button" title="简繁转换">繁</button><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button id="chat_btn" type="button" title="rightside.chat_btn"><i class="fas fa-sms"></i></button><button id="go-up" type="button" title="回到顶部"><i class="fas fa-arrow-up"></i></button></div></div><div id="algolia-search"><div class="search-dialog"><div class="search-dialog__title" id="algolia-search-title">Algolia</div><div id="algolia-input-panel"><div id="algolia-search-input"></div></div><hr/><div id="algolia-search-results"><div id="algolia-hits"></div><div id="algolia-pagination"></div><div id="algolia-stats"></div></div><span class="search-close-button"><i class="fas fa-times"></i></span></div><div id="search-mask"></div></div><div><script src="https://cdn.jsdelivr.net/npm/vue"></script><script src="/blog/js/utils.js"></script><script src="/blog/js/main.js"></script><script src="/blog/js/tw_cn.js"></script><script src="https://cdn.jsdelivr.net/npm/medium-zoom/dist/medium-zoom.min.js"></script><script src="https://cdn.jsdelivr.net/npm/instant.page/instantpage.min.js" type="module"></script><script src="https://cdn.jsdelivr.net/npm/vanilla-lazyload/dist/lazyload.iife.min.js"></script><script src="https://cdn.jsdelivr.net/npm/node-snackbar/dist/snackbar.min.js"></script><script src="/blog/js/search/algolia.js"></script><script>var preloader = {
  endLoading: () => {
    document.body.style.overflow = 'auto';
    document.getElementById('loading-box').classList.add("loaded")
  },
  initLoading: () => {
    document.body.style.overflow = '';
    document.getElementById('loading-box').classList.remove("loaded")

  }
}
window.addEventListener('load',preloader.endLoading())</script><div class="js-pjax"><script>(() => {
  function loadValine () {
    function initValine () {
      let initData = {
        el: '#vcomment',
        appId: 'JC72d1A7XBwC26rGCKMVn5CS-MdYXbMMI',
        appKey: 'xI6bG7FseICz8ShKdmWVe7N1',
      }
      
      const valine = new Valine(initData)
    }

    if (typeof Valine === 'function') initValine() 
    else getScript('https://cdn.jsdelivr.net/npm/valine/dist/Valine.min.js').then(initValine)
  }

  window.pjax ? loadValine() : window.addEventListener('load', loadValine)
})()</script><script>function subtitleType () {
  getScript('https://sdk.jinrishici.com/v2/browser/jinrishici.js').then(() => {
    jinrishici.load(function (result) {
      if (true) {
        var sub = "让自己变得更好; 是解决一切问题的关键,人生是一场修行，走的每一步都要珍惜".length == 0 ? new Array() : "让自己变得更好; 是解决一切问题的关键,人生是一场修行，走的每一步都要珍惜".split(',')
        var content = result.data.content
        var both = sub.unshift(content)
        var typed = new Typed('#subtitle', {
          strings: sub,
          startDelay: 300,
          typeSpeed: 150,
          loop: true,
          backSpeed: 50,
        })
      } else {
        document.getElementById('subtitle').innerHTML = result.data.content
      }
    })
  })
}

if (true) {
  if (typeof Typed === 'function') {
    subtitleType()
  } else {
    getScript('https://cdn.jsdelivr.net/npm/typed.js/lib/typed.min.js').then(subtitleType)
  }
} else {
  subtitleType()
}
</script><script>if (document.getElementsByClassName('mermaid').length) {
  if (window.mermaidJsLoad) mermaid.init()
  else {
    getScript('https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js').then(() => {
      window.mermaidJsLoad = true
      mermaid.initialize({
        theme: 'default',
      })
      false && mermaid.init()
    })
  }
}</script></div><script src="https://cdn.jsdelivr.net/npm/blueimp-md5@2.17.0/js/md5.min.js"></script><script>window.addEventListener('load', () => {
  const changeContent = (content) => {
    if (content === '') return content

    content = content.replace(/<img.*?src="(.*?)"?[^\>]+>/ig, '[图片]') // replace image link
    content = content.replace(/<a[^>]+?href=["']?([^"']+)["']?[^>]*>([^<]+)<\/a>/gi, '[链接]') // replace url
    content = content.replace(/<pre><code>.*?<\/pre>/gi, '[代码]') // replace code
    content = content.replace(/<[^>]+>/g,"") // remove html tag

    if (content.length > 150) {
      content = content.substring(0,150) + '...'
    }
    return content
  }

  const getIcon = (icon, mail) => {
    if (icon) return icon
    let defaultIcon = '?d=https://gitee.com/FIF/pic-beg/raw/master/images/vue/1619248532079-avatar_coment.webp'
    //- let iconUrl = `https://gravatar.loli.net/avatar/${md5(mail.toLowerCase()) + defaultIcon}`
    let iconUrl = 'https://gitee.com/FIF/pic-beg/raw/master/images/vue/1619248532079-avatar_coment.webp'
    return iconUrl
  }

  const generateHtml = array => {
    let result = ''

    if (array.length) {
      for (let i = 0; i < array.length; i++) {
        result += '<div class=\'aside-list-item\'>'

        if (true) {
          const name = 'data-lazy-src'
          result += `<a href='${array[i].url}' class='thumbnail'><img ${name}='${array[i].avatar}' alt='${array[i].nick}'></a>`
        }

        result += `<div class='content'>
        <a class='comment' href='${array[i].url}'>${array[i].content}</a>
        <div class='name'><span>${array[i].nick} / </span><time datetime="${array[i].date}">${btf.diffDate(array[i].date, true)}</time></div>
        </div></div>`
      }
    } else {
      result += '没有评论'
    }

    let $dom = document.querySelector('#card-newest-comments .aside-list')
    $dom.innerHTML= result
    window.lazyLoadInstance && window.lazyLoadInstance.update()
    window.pjax && window.pjax.refresh($dom)
  }

  const getComment = () => {
    const serverURL = 'https://JC72d1A7.api.lncldglobal.com'

    var settings = {
      "method": "GET",
      "headers": {
        "X-LC-Id": 'JC72d1A7XBwC26rGCKMVn5CS-MdYXbMMI',
        "X-LC-Key": 'xI6bG7FseICz8ShKdmWVe7N1',
        "Content-Type": "application/json"
      },
    }

    fetch(`${serverURL}/1.1/classes/Comment?limit=6&order=-createdAt`,settings)
      .then(response => response.json())
      .then(data => {
        const valineArray = data.results.map(function (e) {
          return {
            'avatar': getIcon(e.QQAvatar, e.mail),
            'content': changeContent(e.comment),
            'nick': e.nick,
            'url': e.url + '#' + e.objectId,
            'date': e.updatedAt,
          }
        })
        saveToLocal.set('valine-newest-comments', JSON.stringify(valineArray), 10/(60*24))
        generateHtml(valineArray)
      }).catch(e => {
        const $dom = document.querySelector('#card-newest-comments .aside-list')
        $dom.innerHTML= "无法获取评论，请确认相关配置是否正确"
      }) 
  }

  const newestCommentInit = () => {
    if (document.querySelector('#card-newest-comments .aside-list')) {
      const data = saveToLocal.get('valine-newest-comments')
      if (data) {
        generateHtml(JSON.parse(data))
      } else {
        getComment()
      }
    }
  }

  newestCommentInit()
  document.addEventListener('pjax:complete', newestCommentInit)
})</script><div class="aplayer no-destroy" data-id="000PeZCQ1i4XVs" data-server="tencent" data-type="artist" data-fixed="true" data-mini="true" data-listFolded="false" data-order="random" data-preload="none" data-autoplay="false" pjax="true" muted></div><script defer="defer" id="ribbon" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/canvas-ribbon.min.js" size="150" alpha="0.6" zIndex="-1" mobile="false" data-click="true"></script><script id="canvas_nest" defer="defer" color="0,0,255" opacity="0.7" zIndex="-1" count="99" mobile="false" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/canvas-nest.min.js"></script><script src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/activate-power-mode.min.js"></script><script>POWERMODE.colorful = true;
POWERMODE.shake = true;
POWERMODE.mobile = false;
document.body.addEventListener('input', POWERMODE);
</script><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.css" media="print" onload="this.media='all'"><script src="https://cdn.jsdelivr.net/npm/aplayer/dist/APlayer.min.js"></script><script src="https://cdn.jsdelivr.net/gh/metowolf/MetingJS@1.2/dist/Meting.min.js"></script><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script></div></body></html>